package org.geeks.gscaffeine.func;

import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

@Slf4j
public class CaffeinePopulationT {

  @Test
  public void manual() {
    String key = "Geek-S";

    Cache<String, CacheTarget> cache =
        Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).maximumSize(10_000).build();

    CacheTarget cacheTarget = cache.getIfPresent(key);

    log.info("Result is {}", cacheTarget);

    // Lookup and compute an entry if absent, or null if not computable
    cacheTarget = cache.get(key, k -> createCacheTarget(key));

    log.info("Result is {}", cacheTarget);

    cacheTarget = cache.getIfPresent(key);

    log.info("Result is {}", cacheTarget);

    // Remove an entry
    cache.invalidate(key);

    cacheTarget = cache.getIfPresent(key);

    log.info("Result is {}", cacheTarget);
  }

  @Test
  public void loading() {
    String key = "Geek-S";

    LoadingCache<String, CacheTarget> cache =
        Caffeine.newBuilder()
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .maximumSize(10_000)
            .build(k -> createCacheTarget(key));

    CacheTarget cacheTarget = cache.get(key);

    log.info("Result is {}", cacheTarget);

    cacheTarget =
        cache.get(
            key,
            k -> {
              return createCacheTarget(key);
            });

    log.info("Result is {}", cacheTarget);

    cacheTarget = cache.getIfPresent(key);

    log.info("Result is {}", cacheTarget);

    // Remove an entry
    cache.invalidate(key);

    cacheTarget = cache.getIfPresent(key);

    log.info("Result is {}", cacheTarget);
  }

  @Test
  public void asyncLoading() throws Exception {
    String key = "Geek-S";

    AsyncLoadingCache<String, CacheTarget> cache =
        Caffeine.newBuilder()
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .maximumSize(10_000)
            .buildAsync(k -> createCacheTarget(key));

    CompletableFuture<CacheTarget> cacheTarget = cache.get(key);

    log.info("Result is {}", cacheTarget.get());

    // Remove an entry
    cache.synchronous().invalidate(key);

    cacheTarget = cache.getIfPresent(key);

    log.info("Result is {}", cacheTarget);
  }

  CacheTarget createCacheTarget(String key) {
    return CacheTarget.builder().name("Cache of " + key).build();
  }

  @Data
  @Builder
  static class CacheTarget {

    private String name;
  }
}
